/****************************************************************************/
/***                                                                      ***/
/***   (C) 2012-2014 Dierk Ohlerich et al., all rights reserved.          ***/
/***                                                                      ***/
/***   Released under BSD 2 clause license, see LICENSE.TXT               ***/
/***                                                                      ***/
/****************************************************************************/

mtrl PnShader 
{
  permute Wireframe;

  struct ia2vs
  {
    float3 pos : POSITION;
    float3 norm : NORMAL;
    float2 uv0 : TEXCOORD0;
  };

  struct vs2hs
  {
    float3 pos : POSITION;
    float3 norm : NORMAL;
    float2 uv0 : TEXCOORD0;
  };

  struct tess
  {
    float edges[3] : SV_TessFactor;
    float inside : SV_InsideTessFactor;

    float3 b210 : TEXCOORD0;
    float3 b120 : TEXCOORD1;
    float3 b021 : TEXCOORD2;
    float3 b012 : TEXCOORD3;
    float3 b102 : TEXCOORD4;
    float3 b201 : TEXCOORD5;
    float3 b111 : TEXCOORD6;

    float3 n110 : TEXCOORD7;
    float3 n011 : NORMAL;
    float3 n101 : TANGENT;
  };

  struct hs2ds
  {
    float3 pos : POSITION;
    float3 norm : NORMAL;
    float2 uv0 : TEXCOORD0;
  };

  struct ds2gs
  {
    float4 tpos : POSITION;
    float4 color : COLOR0;
    float2 uv0 : TEXCOORD0;
  };

  struct gs2ps
  {
    float4 tpos : SV_Position;
    float4 color : COLOR;
    float2 uv0 : TEXCOORD0;
  };

  cbuffer cbh0 : hs(0) : register(0)
  {
    row_major float4x4 MS2SS;
    float3 txx;
    float Quality;
  };

  cbuffer cbd0 : ds(0) : register(0)
  {
    row_major float4x4 MS2SS;
    float3 ldir;
  };
  
  vs hlsl5
  {
    void main(in ia2vs i,out vs2hs o)
    {
      o.pos = i.pos;
      o.norm = i.norm;
      o.uv0 = i.uv0;
    }
  };

  hs hlsl5
  {
    float tessfactor1(float3 p0,float3 p1)
    {
      float4 r0 = mul(MS2SS,float4(p0,1));
      float4 r1 = mul(MS2SS,float4(p1,1));
      return length(r0.xy/r0.w-r1.xy/r1.w)*Quality;
    } 

    float tessfactor(float3 p0,float3 p1)
    {
      float3 center = (p0+p1)*0.5;
      float radius = length(p0-p1)*0.5;

      float4 r0 = mul(MS2SS,float4(center,1));
      center += radius*txx;
      float4 r1 = mul(MS2SS,float4(center,1));
      return length(r0.xy/r0.w-r1.xy/r1.w)*Quality;
    } 

    void mainc(in InputPatch<vs2hs,3> i,out tess o)
    { 
      o.edges[0] = tessfactor(i[1].pos,i[2].pos);
      o.edges[1] = tessfactor(i[2].pos,i[0].pos);
      o.edges[2] = tessfactor(i[0].pos,i[1].pos);
      o.inside = (o.edges[0]+o.edges[1]+o.edges[2])/6;

      float3 p1 = i[0].pos; 
      float3 p2 = i[1].pos;
      float3 p3 = i[2].pos;
      float3 n1 = normalize(i[0].norm);
      float3 n2 = normalize(i[1].norm);
      float3 n3 = normalize(i[2].norm);

      o.b210 = (2*p1+p2 - dot((p2-p1),n1)*n1);
      o.b120 = (2*p2+p1 - dot((p1-p2),n2)*n2);
      o.b021 = (2*p2+p3 - dot((p3-p2),n2)*n2);
      o.b012 = (2*p3+p2 - dot((p2-p3),n3)*n3);
      o.b102 = (2*p3+p1 - dot((p1-p3),n3)*n3);
      o.b201 = (2*p1+p3 - dot((p3-p1),n1)*n1);

      float3 e = (o.b210+o.b120+o.b021+o.b012+o.b102+o.b201);
      float3 v = (p1+p2+p3);
      o.b111 = e*0.5-v;

      float vl2;
      vl2 = 4*dot(p2-p1,n1+n2)/dot(p2-p1,p2-p1);
      o.n110 = normalize(n1+n2-vl2*(p2-p1));
      vl2 = 4*dot(p3-p2,n2+n3)/dot(p3-p2,p3-p2);
      o.n011 = normalize(n2+n3-vl2*(p3-p2));
      vl2 = 4*dot(p1-p3,n3+n1)/dot(p1-p3,p1-p3);
      o.n101 = normalize(n3+n1-vl2*(p1-p3));
    }
    [domain("tri")]
    [partitioning("fractional_odd")]
    [outputtopology("triangle_cw")]
    [outputcontrolpoints(3)]
    [patchconstantfunc("mainc")]
    [maxtessfactor(9.0)]
    hs2ds main(in InputPatch<vs2hs,3> i,
               uint id : SV_OutputControlPointID)
    {
      hs2ds o;
      o.pos = i[id].pos;
      o.norm = i[id].norm;
      o.uv0 = i[id].uv0;
      return o;
    }
  };

  ds hlsl5 
  {
    [domain("tri")]
    void main(in tess c,in OutputPatch<hs2ds,3> i,
              in float3 bc : SV_DomainLocation,
              out ds2gs o)
    {
      float3 pos,norm;
      float u = bc.x;
      float v = bc.y;
      float w = bc.z;

      pos = i[0].pos  * u*u*u 
          + i[1].pos  *     v*v*v
          + i[2].pos  *         w*w*w
          + c   .b210 * u*u*v      
          + c   .b120 * u  *v*v    
          + c   .b201 * u*u    *w  
          + c   .b021 *     v*v*w  
          + c   .b102 * u      *w*w
          + c   .b012 *     v  *w*w
          + c   .b111 * u  *v  *w  ;

      norm = i[0].norm * u*u
           + i[1].norm *   v*v
           + i[2].norm *     w*w
           + c.   n110 * u*v
           + c.   n011 *   v*w
           + c.   n101 * u  *w;
      norm = normalize(norm);

//      norm   = i[0].norm*bc.x + i[1].norm*bc.y + i[2].norm*bc.z;
      o.uv0  = i[0].uv0 *bc.x + i[1].uv0 *bc.y + i[2].uv0 *bc.z;
      o.color.xyz = saturate(dot(norm,ldir)*0.75+0.25);
      o.color.w = 1;
      o.tpos = mul(MS2SS,float4(pos,1)); 
    }
  };

  gs hlsl5
  {
    pif(Wireframe)
    {
      [maxvertexcount(4)]
      void main(triangle ds2gs i[3],inout LineStream<gs2ps> os)
      {
        gs2ps o;

        for(uint n=0;n<4;n++)
        {
          o.tpos = i[n%3].tpos;
          o.color = i[n%3].color;
          o.uv0 = i[n%3].uv0;
          os.Append(o);
        }
      }
    }
    pif(!Wireframe)
    {
      [maxvertexcount(3)]
      void main(triangle ds2gs i[3],inout TriangleStream<gs2ps> os)
      {
        gs2ps o;

        for(uint n=0;n<3;n++)
        {
          o.tpos = i[n].tpos;
          o.color = i[n].color;
          o.uv0 = i[n].uv0;
          os.Append(o);
        }
      }
    }
  };

  ps hlsl5
  {
    void main(in gs2ps i,out float4 r:SV_Target)
    {
      r = i.color;
    }
  };
} 

/****************************************************************************/
